package cn.niceff.middleware.dynamic.thread.pool.sdk.config;

import cn.niceff.middleware.dynamic.thread.pool.sdk.domain.IPoolService;
import cn.niceff.middleware.dynamic.thread.pool.sdk.domain.PoolServiceImpl;
import cn.niceff.middleware.dynamic.thread.pool.sdk.domain.model.entity.ThreadPoolConfigEntity;
import cn.niceff.middleware.dynamic.thread.pool.sdk.domain.model.valobj.RegistryEnumVO;
import cn.niceff.middleware.dynamic.thread.pool.sdk.registry.IRegistry;
import cn.niceff.middleware.dynamic.thread.pool.sdk.registry.redis.RedisRegistry;
import cn.niceff.middleware.dynamic.thread.pool.sdk.trigger.job.ThreadPoolReportJob;
import cn.niceff.middleware.dynamic.thread.pool.sdk.trigger.listener.ThreadPoolConfigListener;
import org.redisson.Redisson;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自动配置
 *
 * @author 23863
 */
@Configuration
@EnableConfigurationProperties(DynamicThreadPoolAutoConfigProperties.class)
@EnableScheduling
public class DynamicThreadPoolAutoConfig {
    private final Logger logger = LoggerFactory.getLogger(DynamicThreadPoolAutoConfig.class);

    private String applicationName;

    /**
     * 注册一个RedissonClient Bean
     *
     * @param properties 动态线程池配置属性
     * @return RedissonClient 实例
     */
    @Bean("redisClient")
    public RedissonClient redissonClient(DynamicThreadPoolAutoConfigProperties properties) {
        Config config = new Config();
        // 根据需要可以设定编解码器；https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96
        config.setCodec(JsonJacksonCodec.INSTANCE);

        config.useSingleServer()
                .setAddress("redis://" + properties.getHost() + ":" + properties.getPort())
                .setPassword(properties.getPassword())
                .setConnectionPoolSize(properties.getPoolSize())
                .setConnectionMinimumIdleSize(properties.getMinIdleSize())
                .setIdleConnectionTimeout(properties.getIdleTimeout())
                .setConnectTimeout(properties.getConnectTimeout())
                .setRetryAttempts(properties.getRetryAttempts())
                .setRetryInterval(properties.getRetryInterval())
                .setPingConnectionInterval(properties.getPingInterval())
                .setKeepAlive(properties.isKeepAlive())
        ;

        RedissonClient redissonClient = Redisson.create(config);

        logger.info("动态线程池，注册器（redis）链接初始化完成。{} {} {}", properties.getHost(), properties.getPoolSize(), !redissonClient.isShutdown());

        return redissonClient;
    }

    @Bean
    public IRegistry redisRegitry(RedissonClient redisClient) {
        return new RedisRegistry(redisClient);
    }

    @Bean
    public ThreadPoolReportJob threadPoolReportJob(IRegistry registry, IPoolService poolService) {
        return new ThreadPoolReportJob(poolService, registry);
    }

    @Bean
    public ThreadPoolConfigListener threadPoolConfigListener(IRegistry registry, IPoolService poolService) {
        return new ThreadPoolConfigListener(poolService, registry);
    }

    @Bean
    public RTopic threadPoolConfigListnener(RedissonClient redissonClient, ThreadPoolConfigListener listener) {
        RTopic topic = redissonClient.getTopic(RegistryEnumVO.DYNAMIC_THREAD_POOL_REDIS_TOPIC.getKey() + "_" + applicationName);
        topic.addListener(ThreadPoolConfigEntity.class, listener);
        return topic;
    }


    /**
     * 注册一个PoolService Bean
     *
     * @param applicationContext    Spring 应用程序上下文
     * @param threadPoolExecutorMap 线程池执行器映射表, 自动注入
     * @return PoolServiceImpl 实例
     * <p>
     * 该方法通过Spring的@Bean注解注册一个名为"pollService"的PoolService Bean。
     * 首先，从Spring的应用程序上下文中获取应用程序名称，如果未设置则默认为"dynamic-thread-pool"。
     * 然后，记录一条日志信息表示DynamicThreadPoolAutoConfig初始化成功。
     * 最后，创建一个新的PoolService实例，并将应用程序名称和线程池执行器映射表作为参数传递给它，然后返回该实例。
     */
    @Bean("pollService")
    public PoolServiceImpl registePoolServiceBean(ApplicationContext applicationContext, Map<String, ThreadPoolExecutor> threadPoolExecutorMap) {
        applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");
        if (!StringUtils.hasText(applicationName)) {
            applicationName = "dynamic-thread-pool";
        }
        logger.info("DynamicThreadPoolAutoConfig 初始化成功");
        return new PoolServiceImpl(applicationName, threadPoolExecutorMap);
    }


}
